#include "AlgorithmStats.hpp"
#include "GraphExploration.hpp"
#include "GraphDatabase.hpp"
#include "GraphFunctions.hpp"
#include <algorithm>
#include <numeric>
#include <iostream>
#include <fstream>
#include "ullman.hpp"

using namespace std;
using namespace boost;
using namespace TopologicalLearner;

//----------------------------------------------------------------
double AlgorithmStats::TestAll(TestingSet& kT, Predictor* pPredictor, string sFilename)
{
    int iCorrect = 0;
    kT.iSuccIDs.clear();
    kT.iFailedIDs.clear();

    ofstream out(sFilename.c_str(), ios_base::out);


    out << kT.m_PGSizes.size() << endl;
    for(unsigned int i=0; i < kT.m_PGSizes.size(); i++)
        out << kT.m_PGSizes[i] << endl;

    int iCorrectTmp = 0;
    int k = 0;

    const GraphDatabase* D = pPredictor->GetDatabase();

    /*
    for(int i=0; i < 14; i++)
        k += kT.m_PGSizes[i];*/

    int iM = 1;
    bool isUnique = pPredictor->GetDatabase()->IsUnique();

    for(unsigned int i=0; i < kT.m_PGSizes.size(); i++)
    {
        iCorrectTmp = 0;

        for(unsigned int j=0; j < kT.m_PGSizes[i]; j++)
        {
    //for(int k=0; k < kT.m_PGs.size(); k++)
    //{


/*
            GraphHandler::Instance().m_kPartialG = kT.m_PGs[k].second;
            GraphHandler::Instance().m_pEGraph = &GraphHandler::Instance().GetGraph(kT.m_PGs[k].first);
            cout << "i: " << i << ", j:" << j << endl;

            GraphHandler::Instance().iExcludeGraph = kT.m_PGs[k].first;*/

            for(int z = 0; z < iM; z++)
            {
                //cout << "Calling predict" << endl;

                /*
                if(!bBForce)
                    //GraphHandler::Instance().m_kPartialG = GraphHandler::Instance().ExampleStepPredict2(&GraphHandler::Instance().m_kPartialG);
                    GraphHandler::Instance().m_kPartialG = GraphHandler::Instance().ExampleStepPredict2Preprocessed(&GraphHandler::Instance().m_kPartialG);
                else
                    GraphHandler::Instance().m_kPartialG = GraphHandler::Instance().BruteForcePredict(&GraphHandler::Instance().m_kPartialG);
*/
                //if( GraphHandler::Instance().m_bCorrectPrediction )

                //D.GetGraph(kT.m_PGs[k].first)
                pPredictor->SetExcludeGraph(kT.m_PGs[k].first);
                EditOpDist kResDist = pPredictor->Predict(kT.m_PGs[k].second);
                double dBest = -1;
                EditOp kBest;

                EditOpDist::iterator it;
                for(it = kResDist.begin(); it != kResDist.end(); it++ )
                {
                    if( it->second > dBest )
                    {
                        dBest = it->second;
                        kBest = it->first;
                    }
                }

                Graph gResultingG;
                if(isUnique){
                 gResultingG = GraphFunctions::ApplyEditOp(kT.m_PGs[k].second, kBest);
                }
                else{
                        gResultingG = GraphFunctions::ApplyEditOp(kT.m_PGs[k].second, kBest, false);
                }
/*
                GraphFunctions::SaveGraph("partial.dot", kT.m_PGs[k].second, D);
                GraphFunctions::SaveGraph("predicted.dot", gResultingG, D);
                GraphFunctions::SaveGraph("full.dot", D->GetGraph(kT.m_PGs[k].first), D);
                cout << "Prob:" << dBest << endl;
*/
                // dBest = -1 means that no prediction was found
                bool isSubgraphIsomorphic = false;
                bool isGraphEqual = false;

                if(isUnique){
                    isSubgraphIsomorphic = GraphFunctions::IsSubgraphContained(gResultingG,D->GetGraph(kT.m_PGs[k].first)) ;
                    isGraphEqual = GraphFunctions::GraphEqual(gResultingG, kT.m_PGs[k].second);
                }
                else {
                    // If not we do an ullman
                    std::vector<std::pair<size_t,size_t> > mapping;
                    VertexLabelPredicate alabel(gResultingG,D->GetGraph(kT.m_PGs[k].first));
                    trueEdgePredicate blabel;
                    // If it's not isomorphic, return
                     isSubgraphIsomorphic = ullmann(gResultingG,D->GetGraph(kT.m_PGs[k].first), alabel, blabel, mapping);
                      isGraphEqual = GraphFunctions::GraphEqual(gResultingG, kT.m_PGs[k].second,false);
                }

                if( isSubgraphIsomorphic
                   && !isGraphEqual && dBest != -1 )
                {
                    kT.iSuccIDs.push_back(k);
                    iCorrect++;
                    iCorrectTmp++;
                }
                else
                    kT.iFailedIDs.push_back(k);
            }



            k++;
        }
        if( kT.m_PGSizes[i] != 0 )
        {
        // New graph size, save current
        out << (double)iCorrectTmp / (double)(kT.m_PGSizes[i] * iM) << endl;
        cout << (double)iCorrectTmp / (double)(kT.m_PGSizes[i] * iM) << endl;
        }

    }

    out.close();

    return (double)iCorrect / (double)(kT.m_PGs.size() * iM);
}
//----------------------------------------------------------------
/*
int AlgorithmStats::TestAllGED(TestingSet kT, bool bBForce)
{

    int iTotalDist = 0;
    int iM = 2;
    for(int i=0; i < kT.m_PGs.size(); i++)
    {
        GraphHandler::Instance().m_kPartialG = kT.m_PGs[i].second;
        GraphHandler::Instance().m_pEGraph = &GraphHandler::Instance().GetGraph(kT.m_PGs[i].first);
        for(int j=0; j < iM; j++)
        {
            if(!bBForce)
                GraphHandler::Instance().m_kPartialG = GraphHandler::Instance().ExampleStepPredict2(&GraphHandler::Instance().m_kPartialG);
            else
                GraphHandler::Instance().m_kPartialG = GraphHandler::Instance().BruteForcePredict(&GraphHandler::Instance().m_kPartialG);
        }
        iTotalDist += GraphHandler::Instance().EditDistance(GraphHandler::Instance().m_kPartialG, *GraphHandler::Instance().m_pEGraph);
    }

    return iTotalDist;
}
*/
